/*
 * zenit-r1.c
 *
 * Copyright (C) 2010  Ruslan Mikhaylenko
 */

#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <curses.h>
#include <stdlib.h>

#ifndef KEY_RESIZE
#define KEY_RESIZE 0632
#endif

#define MAX_SCRIPTS 100
#define MAX_APPS 50

int MA, MS, SPA, sl; // REAL COUNTs OF APP, SCRIPTS, scripts per app, index of selected application
int slen, alen; //Max strlen of script, app

const char *script_dir = "/export/home/shafmar/mirus/scripts";
char *script_names[MAX_SCRIPTS];
char *app_names[MAX_APPS];
char *script_per_app[MAX_SCRIPTS];

static int cmpstringp(const void *p1, const void *p2) 
{
    return strcmp(* (char * const *) p1, * (char * const *) p2);
}


/*****************************************************************************/
/*****  Count the elements  **************************************************/
int count_elements(char **array, int max)
{

    int count=0;
    for (int i=0; i<max; i++)
        if (array[i]) count++;
    return count;
}

/*****************************************************************************/
/*****  Scan directory with scripts and make the array of script names  ******/
int scanscripts(const char *dr) 
{

    DIR *dir;
    struct dirent *ent;
    struct stat sb;

    if ((dir = opendir(dr)) == NULL) {
        fprintf(stderr, "Failed to open %s: %s\n", dr, strerror(errno));
        return 1;
    }
    if (chdir(dr) == -1) {
        fprintf(stderr, "Failed to chdir %s: %s\n", dr, strerror(errno));
        return 1;
    }

    int i=0;
    while ((ent = readdir(dir))) {
        if (stat(ent->d_name, &sb)) {
            fprintf(stderr, "Stat failed %s: %s\n", ent->d_name, strerror(errno));
            return 1;
        }
        if ((sb.st_mode & S_IFMT) == S_IFREG) {
            script_names[i] = (char *)calloc(1, strlen(ent->d_name)+1);
            sprintf(script_names[i], "%s", ent->d_name);
            //printf("%s\n", script_names[i]);
            i++;
        }
    }
    closedir(dir);
    qsort(&script_names, count_elements(script_names,MAX_SCRIPTS), sizeof(char *), cmpstringp);
    return 0;
}

/*****************************************************************************/
/*****  Make the array of main applications  *********************************/
int get_main_apps(int m) 
{

    int appcount=0;
    char *buffer;

    for (int i=0; i<m; i++) {
        buffer = (char *)calloc(1, strlen(script_names[i])+1);
        sprintf(buffer, "%s", script_names[i]);
		strtok(buffer, "-");
        if (appcount) {
            if ( !strcmp(buffer, app_names[appcount-1]) ) {
                free(buffer);
                continue;
            }
        }

        app_names[appcount] = (char *) calloc(1, strlen(buffer)+1);
        sprintf(app_names[appcount], "%s", buffer);
	//printf("%s\n", app_names[appcount]);
        free(buffer);
        appcount++;
    }

    return 0;
}

/*****************************************************************************/
/*****  Select scripts per application  **************************************/
void  select_scripts_per_app(char *appname) 
{
    char *buffer;
    int k=0;	
    for (int i=0; i<MS; i++) {
        buffer = (char *)calloc(1, strlen(script_names[i])+1);
        sprintf(buffer, "%s", script_names[i]);
        strtok(buffer, "-");
        if ( !strcmp(buffer, appname) ) {
		script_per_app[k] = (char *) calloc(1, strlen(script_names[i])+1);
		sprintf(script_per_app[k], "%s", script_names[i]);
		++k;
	}
        free(buffer);
    }
}

/*****************************************************************************/
/***** Count max lengths of script, apps *************************************/
void count_arr_len(int &s, int &a)
{
	static int j = 0;
	static int k = 0;
	for (int i=0; i<MS; i++) {
		if(strlen(script_names[i]) > j) j=strlen(script_names[i]);
	}
	for (int l=0; l<MA; l++) {
		if(strlen(app_names[l]) > k) k=strlen(app_names[l]);
	}
	s=j;
	a=k;
}

/*****************************************************************************/
/***** Print needed count of spaces to align the highlighting line ***********/
void prs(WINDOW *win, int c)
{
	for(int i=0; i<=c; i++) wprintw(win, "%s", " ");
}
/*****************************************************************************/
/*****  Print the menu  ******************************************************/
void print_menu(WINDOW *win, int mode, int highlight)
{

	int x = 2;
	int y = 4;
	mvwprintw(win, 1, 7,  "%s", "Zenit 1.0        Copyright (C) 2010 Ruslan Mikhaylenko");
	mvwprintw(win, 2, 7,  "%s", "[q - quiet. UP, DOWN, LEFT - navigate. ENTER - select]");

	if(mode == 0){ //Display the applications
		for(int i=0; i<MA; i++) {
			if(i==highlight) { 
				wattron(win, A_REVERSE); 
				mvwprintw(win, y, x,  "%s", app_names[i]);
				//diff=alen;
				prs(win, alen-strlen(app_names[i]));
				wattroff(win, A_REVERSE);
			}
			else mvwprintw(win, y, x, "%s\n", app_names[i]);
		++y;
		}
	}

	else { // Show the scripts per selected application
		for(int i=0; i<SPA; i++) {
			if(i==highlight) { 
				wattron(win, A_REVERSE);
				mvwprintw(win, y, x,  "%s", script_per_app[i]);
				prs(win, slen-strlen(script_per_app[i]));
				wattroff(win, A_REVERSE);
			}
			 else mvwprintw(win, y, x, "%s\n", script_per_app[i]);
		++y;
		}
	}
//	wborder(win, '|', '|', '-','-',' ',' ',' ',' ');
	wrefresh(win);
}


/*****************************************************************************/
/*****  M  A  I  N  **********************************************************/
int main(int argc, char *argv[]) 
{

	if(scanscripts(script_dir)) return 1;
		
	MS = count_elements(script_names, MAX_SCRIPTS);
	get_main_apps(MS);
	MA = count_elements(app_names, MAX_APPS);
	count_arr_len(slen, alen);
	initscr();
	//if(!has_colors()) { endwin(); fprintf(stderr, "Your derminal does not support colors.\n"); return 1;}

	clear();
	cbreak();
	noecho();
	curs_set(0);
	WINDOW* list;
	list = newwin(0, 0, 0, 0);
	keypad(list, TRUE);
	
	int mode = 0; // default mode to show app names, 1 - scripts.
	int h	 = 0; // highlight the first element
	print_menu(list, mode, h);
	int ch = 0;
	bool done = FALSE;
	bool leave = FALSE;
	
	while (true)
	{
		ch = wgetch(list);
		if(ch == 113) break;
		if(!mode) {
			switch(ch) {
				case KEY_UP:
					(h == 0) ? h=MA-1 : --h; 
					break;
				case KEY_DOWN:
					(h == (MA-1)) ? h = 0 : ++h;
					break;
				case KEY_RESIZE:
					wclear(list);
					break;
				case 10:
					wclear(list);
					mode	= 1;
					select_scripts_per_app(app_names[h]);
					SPA = count_elements(script_per_app, MAX_SCRIPTS); 
					h 	= 0;
					break;
				default:
					break;
			}
		}
		
		else if(mode) {
			switch(ch) {
				case KEY_UP:
					(h == 0) ? h=SPA-1 : --h;
				        break;
                                case KEY_DOWN:
					(h == (SPA-1)) ? h = 0 : ++h;
				        break;
				case KEY_LEFT:
					for (int i=0; i<SPA; i++) {script_per_app[i] = NULL; free(script_per_app[i]);}
					wclear(list);
					mode = 0;
					h    = 0;					
					break;
                                case 10:
					done = TRUE;
                                        break;
				case KEY_RESIZE:
					wclear(list);
                                default:
                                        break;

			}
		}
		
		
	if (done) break;
	print_menu(list, mode, h);
	}
    	
    delwin(list);
    endwin();
	
	char *zenit;
    if(done) {	 
    	zenit = (char *) calloc(1, strlen(script_per_app[h])+strlen("./")+1);
    	sprintf(zenit, "%s%s", "./", script_per_app[h]);		
    }

    //clear the arrays
    for (int i=0; i<MS; i++) free(script_names[i]);
    for (int i=0; i<MA; i++) free(app_names[i]);
    for (int i=0; i<SPA; i++) free(script_per_app[i]);

	if(done) system(zenit);
    return 0;
}

















